const soundMap = {
  move: document.getElementById('moveSound'),
  capture: document.getElementById('captureSound'),
  checkmate: document.getElementById('checkmateSound')
};

  class ChessAI {
    #engine = null;
    #currentResolve = null;
    #openingBook = {
      'e2e4': '国王开局',
      'd2d4': '后翼弃兵',
      'g1f3': '罗马尼亚开局',
      'c2c4': '英国式开局',
      'e7e5': '开放游戏',
      'd7d5': '封闭游戏'
    };
  
    constructor(color, depth = 18) {
      this.color = color;
      this.depth = depth;
      this.currentEval = 0;
      this.pv = '';
      this.evalHistory = [];
      this.#initEngine();
    }
  
    #initEngine() {
      this.#engine = new Worker('./stockfish.js');
      this.#engine.postMessage('uci');
      this.#engine.postMessage(`setoption name Threads value ${navigator.hardwareConcurrency || 4}`);
      this.#engine.postMessage('setoption name Hash value 512');
      this.#engine.onmessage = (e) => this.#handleEngineMessage(e.data);
    }
  
    #handleEngineMessage(data) {
      if (data.startsWith('info')) this.#parseAnalysis(data);
      if (data.startsWith('bestmove') && this.#currentResolve) {
        const move = data.split(' ')[1];
        this.#currentResolve(move);
      }
    }
  
    #parseAnalysis(data) {
      const depthMatch = data.match(/depth (\d+)/);
      const cpMatch = data.match(/cp (-?\d+)/);
      const pvMatch = data.match(/pv (.+)/);
  
      this.depth = depthMatch ? parseInt(depthMatch[1]) : this.depth;
      this.currentEval = cpMatch ? parseInt(cpMatch[1]) / 100 : 0;
      this.pv = pvMatch ? pvMatch[1].split(' ').slice(0, 3).join(' ') : '';
      this.evalHistory.push(this.currentEval);
      
      this.#updateUIPanels();
      this.#detectOpening();
    }
  
    #updateUIPanels() {
      document.getElementById(`${this.color}-depth`).textContent = this.depth;
      document.getElementById(`${this.color}-eval`).textContent = this.currentEval.toFixed(2);
      document.getElementById(`${this.color}-winrate`).textContent = this.#calculateWinRate();
      document.getElementById(`${this.color}-pv`).textContent = this.pv;
    }
  
    #detectOpening() {
      const firstMove = this.pv.split(' ')[0];
      const openingName = this.#openingBook[firstMove] || '未知开局';
      document.getElementById(`${this.color}-opening`).textContent = openingName;
    }
  
    #calculateWinRate() {
      const winChance = 1 / (1 + Math.exp(-this.currentEval / 2.5));
      return `${(winChance * 100).toFixed(1)}%`;
    }
  
    async getBestMove(fen) {
      return new Promise(resolve => {
        this.#currentResolve = resolve;
        this.#engine.postMessage(`position fen ${fen}`);
        this.#engine.postMessage(`go depth ${this.depth} movetime 4000`);
      });
    }
  
    terminate() {
      this.#engine.terminate();
    }
  
}

class ChessGame {
  #board = null;
  #game = null;
  #ais = {};
  #state = {
    isRunning: false,
    isPaused: false,
    humanPlayer: 'none',
    moveDelay: 1800,
    showAnalysis: true,
    showArrows: true
  };
  evalChart = null;

  constructor() {
    this.#initBoard();
    this.#game = new Chess();
    this.#ais = { w: new ChessAI('blue'), b: new ChessAI('red') };
  }

  // === 私有方法完整实现 ===
  #logMove(move, source) {
    const iconMap = {
      blue: '🔵',
      red: '🔴',
      human: '👤'
    };
    const icon = iconMap[source] || '⚫';
    
    const logEntry = document.createElement('div');
    logEntry.className = 'log-entry';
    logEntry.innerHTML = `
      <span class="log-icon">${icon}</span>
      <span>${new Date().toLocaleTimeString()}</span>
      <strong>${move.san}</strong>
    `;
    
    const logContainer = document.getElementById('gameLog');
    logEntry.style.animation = 'fadeIn 0.3s ease';
    logContainer.appendChild(logEntry);
    logContainer.scrollTop = logContainer.scrollHeight;
  }
  #initBoard() {
    const config = {
      position: 'start',
      pieceTheme: './img/{piece}.png',
      draggable: true,
      orientation: 'white',
      showNotation: true,
      moveSpeed: 300,
      snapbackSpeed: 100,
      snapSpeed: 50,
      onDragStart: (s) => this.#handleDragStart(s),
      onDrop: (s, t) => this.#handleDrop(s, t),
      onSnapEnd: () => this.#board.position(this.#game.fen()),
      onMouseoutSquare: () => this.#clearHighlights(),
      onClick: (s) => this.#handlePieceClick(s)
    };
    this.#board = Chessboard('board', config);
  }

  #handleDragStart(source) {
    if (!this.#state.isRunning || this.#state.isPaused) return false;
    if (this.#state.humanPlayer === 'none') return false;
    if (this.#game.turn() !== this.#state.humanPlayer) return false;
    
    const piece = this.#game.get(source);
    return !!piece && piece.color === this.#state.humanPlayer;
  }

  async #handleDrop(source, target) {
    if (!this.#state.isRunning || this.#state.isPaused) return 'snapback';
    
    try {
      const move = this.#game.move({
        from: source,
        to: target,
        promotion: 'q'
      });

      if (!move) return 'snapback';

      this.#animatePiece(source, target);
      playSound(move.captured ? 'capture' : 'move');
      this.#logMove(move, 'human');
      await this.#makeAIMove();
      this.#updateEvalChart();
      return true;
    } catch (error) {
      console.error('移动失败:', error);
      return 'snapback';
    }
  }

  #animatePiece(from, to) {
    const $piece = $(`#board .square-${from} .piece`);
    $piece.addClass('moving-piece');
    setTimeout(() => {
      $piece.removeClass('moving-piece');
      this.#board.position(this.#game.fen());
    }, 300);
  }

  async #makeAIMove() {
    if (!this.#game.game_over() && this.#game.turn() !== this.#state.humanPlayer) {
      const ai = this.#ais[this.#game.turn()];
      try {
        const move = await ai.getBestMove(this.#game.fen());
        await this.#executeMove(move, ai.color);
        this.#updateEval();
        await new Promise(r => setTimeout(r, this.#state.moveDelay));
      } catch (error) {
        console.error('AI移动失败:', error);
      }
    }
  }

  #executeMove(move, source) {
    return new Promise((resolve) => {
      try {
        const result = this.#game.move(move, { sloppy: true });
        if (!result) {
          this.#log(`无效移动: ${move}`, 'error');
          resolve(false);
          return;
        }
        
        this.#animatePiece(result.from, result.to);
        playSound(result.captured ? 'capture' : 'move');
        this.#logMove(result, source);
        resolve(true);
      } catch (error) {
        console.error('执行移动失败:', error);
        resolve(false);
      }
    });
  }

  #updateEval() {
    const evalDiff = this.#ais.w.currentEval - this.#ais.b.currentEval;
    const position = 50 + Math.min(Math.max(evalDiff * 3, -45), 45);
    document.getElementById('evalIndicator').style.left = `${position}%`;
    this.#drawAIArrows();
  }

  #updateEvalChart() {
    if (!this.evalChart) {
      const ctx = document.getElementById('evalChart').getContext('2d');
      this.evalChart = new Chart(ctx, {
        type: 'line',
        data: {
          labels: Array.from({ 
            length: Math.max(
              this.#ais.w.evalHistory.length, 
              this.#ais.b.evalHistory.length
            ) 
          }, (_, i) => i + 1),
          datasets: [
            {
              label: '蓝方评估',
              borderColor: '#2196F3',
              data: this.#ais.w.evalHistory,
              tension: 0.3,
              pointRadius: 0
            },
            {
              label: '红方评估',
              borderColor: '#FF5252',
              data: this.#ais.b.evalHistory,
              tension: 0.3,
              pointRadius: 0
            }
          ]
        },
        options: {
          responsive: true,
          maintainAspectRatio: false,
          scales: {
            x: {
              display: true,
              title: { display: true, text: '步数' }
            },
            y: {
              display: true,
              title: { display: true, text: '评估值' }
            }
          }
        }
      });
    } else {
      this.evalChart.data.datasets[0].data = this.#ais.w.evalHistory;
      this.evalChart.data.datasets[1].data = this.#ais.b.evalHistory;
      this.evalChart.update();
    }
  }

  #endGame() {
    this.#state.isRunning = false;
    let message = '游戏结束：平局';
    
    if (this.#game.in_checkmate()) {
      message = `胜方：${this.#game.turn() === 'w' ? '红方' : '蓝方'}`;
      playSound('checkmate');
    } else if (this.#game.in_draw()) {
      message = `平局原因：${this.#getDrawReason()}`;
    }
    
    this.#showGameOverModal(message);
    this.#log(message, 'system');
  }

  #getDrawReason() {
    if (this.#game.in_stalemate()) return '逼和';
    if (this.#game.insufficient_material()) return '子力不足';
    return '五十步规则';
  }

  #showGameOverModal(message) {
    const modalHTML = `
      <div class="game-over-modal">
        <div class="modal-content">
          <h2>${message}</h2>
          <p>总步数：${this.#game.history().length}</p>
          <button onclick="this.parentElement.parentElement.remove()">
            <i class="fas fa-times"></i> 关闭
          </button>
        </div>
      </div>
    `;
    document.body.insertAdjacentHTML('beforeend', modalHTML);
  }

  #log(message, type) {
    const colors = {
      system: '#666',
      error: '#f44336',
      blue: '#2196F3',
      red: '#FF5252'
    };
    
    const entry = document.createElement('div');
    entry.style.color = colors[type] || '#000';
    entry.textContent = `[${new Date().toLocaleTimeString()}] ${message}`;
    const logContainer = document.getElementById('gameLog');
    logContainer.appendChild(entry);
    logContainer.scrollTop = logContainer.scrollHeight;
  }

  #clearHighlights() {
    $('#board .square').removeClass('possible-move capture-move');
  }

  #handlePieceClick(source) {
    if (!this.#state.isRunning || this.#state.humanPlayer === 'none') return;
    if (this.#game.turn() !== this.#state.humanPlayer) return;
    
    const piece = this.#game.get(source);
    if (piece?.color === this.#state.humanPlayer) {
      this.#showPossibleMoves(source);
    }
  }

  #showPossibleMoves(source) {
    this.#clearHighlights();
    this.#game.moves({ square: source, verbose: true }).forEach(move => {
      const targetSquare = $(`#board .square-${move.to}`);
      targetSquare.addClass(move.flags.includes('c') ? 'capture-move' : 'possible-move');
    });
  }

  #drawAIArrows() {
    $('.ai-arrow').remove();
    if (!this.#state.showArrows) return;

    [this.#ais.w, this.#ais.b].forEach(ai => {
      const moves = ai.pv.split(' ').slice(0, 2);
      if (moves.length === 2) {
        this.#createArrow(moves[0], moves[1], ai.color);
      }
    });
  }

  #createArrow(from, to, color) {
    const arrow = document.createElement('div');
    arrow.className = `ai-arrow ${color}-arrow`;
    
    const updatePosition = () => {
      const fromEl = $(`.square-${from}`)[0]?.getBoundingClientRect();
      const toEl = $(`.square-${to}`)[0]?.getBoundingClientRect();
      if (!fromEl || !toEl) return;

      const boardRect = $('#board')[0].getBoundingClientRect();
      const angle = Math.atan2(toEl.top - fromEl.top, toEl.left - fromEl.left);
      
      Object.assign(arrow.style, {
        left: `${fromEl.left - boardRect.left + fromEl.width/2}px`,
        top: `${fromEl.top - boardRect.top + fromEl.height/2}px`,
        width: `${Math.hypot(toEl.left - fromEl.left, toEl.top - fromEl.top)}px`,
        transform: `rotate(${angle}rad)`
      });
    };

    $('#board').append(arrow);
    updatePosition();
    $(window).on('resize', updatePosition);
  }

  // === 公共方法 ===
  start() {
    if (this.#state.isRunning) return;
    this.#state.isRunning = true;
    this.#state.isPaused = false;
    this.#log('对战开始!', 'system');

    const gameLoop = async () => {
      while (this.#state.isRunning && !this.#game.game_over()) {
        if (this.#state.isPaused) {
          await new Promise(r => setTimeout(r, 100));
          continue;
        }

        if (this.#game.turn() === this.#state.humanPlayer) {
          await new Promise(r => setTimeout(r, 100));
          continue;
        }

        const ai = this.#ais[this.#game.turn()];
        try {
          const move = await ai.getBestMove(this.#game.fen());
          await this.#executeMove(move, ai.color);
          this.#updateEval();
          await new Promise(r => setTimeout(r, this.#state.moveDelay));
        } catch (error) {
          console.error('AI移动失败:', error);
        }
      }
      this.#endGame();
    };

    gameLoop().catch(error => {
      console.error('游戏循环异常:', error);
      this.#endGame();
    });
  }

  togglePause() {
    this.#state.isPaused = !this.#state.isPaused;
    this.#log(`游戏已${this.#state.isPaused ? '暂停' : '继续'}`, 'system');
    return this.#state.isPaused;
  }

  setHumanPlayer(color) {
    this.#state.humanPlayer = color;
    this.#board.orientation(color === 'w' ? 'white' : 'black');
    this.#log(`玩家选择：${color === 'w' ? '蓝方' : '红方'}`, 'system');
  }

  setMoveDelay(delay) {
    this.#state.moveDelay = Math.max(500, Math.min(3000, delay));
  }

  setShowArrows(value) {
    this.#state.showArrows = value;
    if (value) this.#drawAIArrows();
    else $('.ai-arrow').remove();
  }

  toggleAnalysis() {
    this.#state.showAnalysis = !this.#state.showAnalysis;
    return this.#state.showAnalysis;
  }

  get isRunning() {
    return this.#state.isRunning;
  }
}

// 初始化
$(document).ready(() => {
  window.game = new ChessGame();
  
  $('#startBtn').click(() => game.start());
  $('#pauseBtn').click(function() {
    const isPaused = game.togglePause();
    $(this).html(isPaused ? 
      '<i class="fas fa-play"></i> 继续' : 
      '<i class="fas fa-pause"></i> 暂停'
    );
  });
  $('#resetBtn').click(() => location.reload());
  $('#analysisToggle').click(() => {
    $('.ai-panel').slideToggle();
    game.toggleAnalysis();
  });
  $('#playerSelect').change(function() {
    game.setHumanPlayer($(this).val());
  });
  $('#speedControl').on('input', function() {
    const delay = parseInt($(this).val());
    $('#speedValue').text(`${delay}ms`);
    game.setMoveDelay(delay);
  });
  $('#arrowToggle').change(function() {
    game.setShowArrows(this.checked);
  });
});

function playSound(type) {
  const sound = soundMap[type];
  if (sound) {
    sound.currentTime = 0;
    sound.play().catch(e => console.error('音效播放失败:', e));
  }
}
